package map;

import java.io.FileNotFoundException;
import java.util.ArrayList;

import util.FileOperation;
/**
 * 
 * @Title: CandyLinkedListMap.java 
 * @Package map 
 * @Description: 基于链表的映射实现
 * @author CandyWall   
 * @date 2021年1月6日 下午4:34:20 
 * @version V1.0
 */
public class CandyLinkedListMap<K, V> implements CandyMap<K, V> {
    private class Node {
        public K key;
        public V value;
        public Node next;
        
        public Node(K key, V value, Node next) {
            this.key = key;
            this.value = value;
            this.next = next;
        }
        
        public Node(K key, V value) {
            this(key, value, null);
        }
        
        public Node(K key) {
            this(key, null, null);
        }

        public Node() {
            this(null, null, null);
        }

        @Override
        public String toString() {
            return "Node [key=" + key + ", value=" + value + "]";
        }
    }
    
    private Node dummyHead, tail;
    private int size;
    
    public CandyLinkedListMap() {
        dummyHead = tail = new Node();
        size = 0;
    }

    @Override
    public void add(K key, V value) {
        Node node = getNode(key);
        // 映射中不存在键为key的节点
        if(node == null) {
            dummyHead.next = new Node(key, value, dummyHead.next);
            size++;
        } 
        // 更新旧值为新值
        else {
            node.value = value;
        }
    }

    @Override
    public V remove(K key) {
        Node prev = dummyHead;
        while(prev.next != null) {
            if(key.equals(prev.next.key)) {
                Node delNode = prev.next;
                prev.next = delNode.next;
                delNode.next = null;
                size--;
                return delNode.value;
            }
            prev = prev.next;
        }
        
        return null;
    }

    @Override
    public boolean contains(K key) {
        return getNode(key) != null;
    }

    @Override
    public V get(K key) {
        Node node = getNode(key);
        return node == null ? null : node.value;
    }

    @Override
    public void set(K key, V newValue) {
        Node node = getNode(key);
        if(node == null) {
            throw new RuntimeException("待修改的元素不存在");
        }
        node.value = newValue;
    }

    @Override
    public int getSize() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }
    
    public Node getNode(K key) {
        Node cur = dummyHead.next;
        while(cur != null) {
            if(key.equals(cur.key)) {
                return cur;
            }
            cur = cur.next;
        }
        
        return null;
    }
    
    // 打印映射中的键和值
    public void printMap() {
        Node cur = dummyHead.next;
        while(cur != null) {
            System.out.println("key=" + cur.key + ", value=" + cur.value);
            cur = cur.next;
        }
    }
    
    // 完成词频统计，返回每个单词和对应出现的次数
    public static CandyLinkedListMap<String, Integer> wordCount(ArrayList<String> words) {
        CandyLinkedListMap<String, Integer> wordCountMap = new CandyLinkedListMap();
        for(String word : words) {
            // 如果映射中不包含这个单词，说明这个单词第1次出现，
            // 那么将这个单词添加到映射中
            if(!wordCountMap.contains(word)) {
                wordCountMap.add(word, 1);
            } else {
                wordCountMap.set(word, wordCountMap.get(word) + 1);
            }
        }
        return wordCountMap;
    }
    
    // 从文件中读取到所有的单词，并以ArrayList<String>方式返回
    private static ArrayList<String> readWordsFromFile(String filePath) {
        ArrayList<String> words = new ArrayList<>();
        if(!FileOperation.readFile(filePath, words)) {
            // 加载失败
            try {
                throw new FileNotFoundException("找不到文件");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        } 
        return words;
    }
    
    public static void main(String[] args) {
        ArrayList<String> list = readWordsFromFile("testData/pride-and-prejudice.txt");
        CandyLinkedListMap<String, Integer> wordCountMap = wordCount(list);
        wordCountMap.printMap();
        System.out.println("单词总数：" + list.size());
        System.out.println("不同单词数量：" + wordCountMap.getSize());
        System.out.println("pride出现的次数：" + wordCountMap.get("pride"));
        System.out.println("prejudice出现的次数：" + wordCountMap.get("prejudice"));
    }
}
